const Hook = require('./Hook')

class HookCodeFactory {
    args({after, before} = {}) {
        let allArgs = this.options.args
        // before拼接allArgs
        if (before) allArgs = [before].concat(allArgs)
        // allArgs拼接after
        if (after) allArgs = allArgs.concat(after)
        // ['name','age'] --(to str)--> name,age
        return allArgs.join(',')
    }

    head() {
        return `"use strict";var _context;var _x = this._x;`
    }

    content() {
        let code = `
        var _counter = ${this.options.taps.length};
        var _done = (function (){ _callback(); });
        `
        for (let i = 0; i < this.options.taps.length; i++) {
            code += `var _fn${i} = _x[${i}];_fn${i}(name, age, (function (){
                if (--_counter === 0) _done();
            }));            
            `
        }
        return code
    }

    // instance是hook实例
    // options是{tags:[{},{}],args:[name,age]}
    setup(instance, options) { // 准备后续要用到的数据
        // tapable源码中,这里通过init方法实现
        // 我们这里直接挂载到this上
        this.options = options
        // this._x = [f1,f2,...]
        instance._x = options.taps.map(o => o.fn)
    }

    create() { // 核心是创建可执行的代码体,然后返回
        let fn
        // fn=new Function ("name, age","var _x = this._x, var _fn0 = x[0]; _fn0(name, age);")
        fn = new Function(
            this.args({after: '_callback'}),
            this.head() + this.content()
        )
        return fn
    }
}

let factory = new HookCodeFactory()

class AsyncParallelHook extends Hook {
    constructor(args) {
        super(args)
    }

    compile(options) {
        factory.setup(this, options)
        return factory.create(options)
    }
}

module.exports = AsyncParallelHook